import { Room, Client } from "colyseus";
import { Schema, type, MapSchema, ArraySchema } from "@colyseus/schema"
import Matter, { Engine, Bodies, Body, World } from 'matter-js';
import { Bezier } from "bezier-js";

const COLLISION_CATEGORY = {
  PLAYER: 0x0001,
  BULLET: 0x0002,
  WALL: 0x0004,
  TEXTBOX: 0x0008
};
const CANVAS_WIDTH = 960;
const CANVAS_HEIGHT = 640;

class Player extends Schema {
  @type("number") x = 0;
  @type("number") y = 0;
  @type("number") direction = 0;
  body: Body; // Matter.js物理体
  constructor(x: number = 0, y: number = 0) {
    super();
    this.body = Bodies.circle(x, y, 20, {
      restitution: 0.3,
      frictionAir: 0.01, // 减少空气摩擦
      friction: 0.1,       // 调整地面摩擦
      density: 0.8, // 增加密度控制
      collisionFilter: {
        category: COLLISION_CATEGORY.PLAYER,
        mask: COLLISION_CATEGORY.WALL | COLLISION_CATEGORY.TEXTBOX
      }
    });
    Body.setMass(this.body, 2); // 设置质量
  }
  addBody(engine: Engine) {
    World.add(engine.world, this.body);
  }
}

class Bullet extends Schema {
  @type("number") x: number;
  @type("number") y: number;
  @type("number") direction: number; // 角度（0-360）
  @type("number") speed: number = 10;
  @type("number") life: number = 2000; // 存活时间(ms)
  timestamp: number;
  body: Body; // Matter.js物理体

  constructor(x: number = 0, y: number = 0, direction: number = 0) {
    super();
    this.x = x;
    this.y = y;
    this.direction = direction;
    this.timestamp = Date.now();

    this.body = Bodies.rectangle(x, y, 10, 5, {
      friction: 0,
      restitution: 0.5,
      label: 'bullet', // 方便碰撞检测
      collisionFilter: {
        category: COLLISION_CATEGORY.BULLET,
        mask: COLLISION_CATEGORY.WALL | COLLISION_CATEGORY.TEXTBOX
      }
    });
    const radians = (direction + 90) * (Math.PI / 180);
    Body.setVelocity(this.body, {
      x: Math.cos(radians) * 15,
      y: Math.sin(radians) * 15
    });
  }
  addBody(engine: Engine) {
    World.add(engine.world, this.body);
  }
}

class TextBox extends Schema {
  @type("number") x: number = 0;
  @type("number") y: number = 0;
  @type("number") width: number = 100;
  @type("number") height: number = 100;
  @type("number") direction: number;
  body: Body;

  @type("number") startTime = Date.now();
  @type("number") duration = 5000; // 完整路径耗时(ms)
  @type("boolean") loop = false; // 是否循环
  public curve: Bezier; // 贝塞尔曲线实例
  @type("number") hitCount: number = 0; // 新增命中状态
  constructor(x: number = 0, y: number = 0, engine: Engine) {
    super();
    this.x = x;
    this.y = y;

    this.body = Bodies.rectangle(x, y, this.width, this.height, {
      isStatic: false,
      label: 'textbox',
      collisionFilter: {
        category: COLLISION_CATEGORY.TEXTBOX,
        mask: COLLISION_CATEGORY.PLAYER | COLLISION_CATEGORY.BULLET
      }
    })

    World.add(engine.world, [this.body]);
    this.initPath();
  }
  initPath() {
    const [p1, p2, p3, p4] = getPoints(CANVAS_WIDTH, CANVAS_HEIGHT)
    this.x = p1[0]
    this.y = p1[1]

    this.curve = new Bezier([p1, p2, p3, p4].map(p => ({ x: p[0], y: p[1] })));
  }
}

// 物理引擎管理器（包含TS类型）
class PhysicsManager {
  engine: Engine;

  constructor(width: number, height: number) {
    this.engine = Engine.create({
      gravity: { x: 0, y: 0 }
    });
    this.configureWorld(width, height);
  }

  private configureWorld(width: number, height: number) {
    // 设置物理世界
    World.add(this.engine.world, [
      Bodies.rectangle(width / 2, -10, width, 20, {
        isStatic: true,
        collisionFilter: {
          category: COLLISION_CATEGORY.WALL,
          mask: COLLISION_CATEGORY.PLAYER | COLLISION_CATEGORY.BULLET
        }
      }),
      Bodies.rectangle(-10, height / 2, 20, height, { isStatic: true }), // 左侧
      Bodies.rectangle(width / 2, height + 10, width, 20, { isStatic: true }), // 底部
      Bodies.rectangle(width + 10, height / 2, 20, height, { isStatic: true }) // 右侧
    ]);
  }
}

class GameState extends Schema {
  @type({ map: Player }) players = new MapSchema<Player>();
  @type([Bullet]) bullets = new ArraySchema<Bullet>();
  @type([TextBox]) textboxes = new ArraySchema<TextBox>();
}

export class GameRoom extends Room<GameState> {
  maxClients = 4; // 限制4个玩家
  length = 5;
  physics: PhysicsManager; // 物理引擎实例

  onCreate() {
    // 初始化物理世界 (960x640)
    this.physics = new PhysicsManager(960, 640);
    this.setState(new GameState())

    const pos = [
      [30, 40],
      [-200, -100],
      [-150, 20],
      [90, -90],
      [100, 100],
      [100, 100],
      [100, 100],
      [100, 100],
      [100, 100],
      [100, 100],
      [100, 100],
    ]
    for (let i = 0; i < pos.length; i++) {
      const box = new TextBox(pos[i][0], pos[i][1], this.physics.engine);
      this.state.textboxes.push(box);
    }
    this.setSimulationInterval((deltaTime) => {
      Engine.update(this.physics.engine, deltaTime);
      this.updateBezierPaths(); // 新增路径更新
      this.syncPhysicsState();
    }, 16)

    // 修改移动处理（使用物理力）
    // this.onMessage("move", (client, direction) => {
    //   const player = this.state.players.get(client.sessionId);
    //   const force = { x: 0, y: 0 };

    //   switch (direction) {
    //     case "left": force.x = -0.02; break;
    //     case "right": force.x = 0.02; break;
    //     case "up": force.y = -0.02; break;
    //     case "down": force.y = 0.02; break;
    //   }

    //   Body.applyForce(player.body, player.body.position, force);
    //   // 在applyForce后添加速度监控
    //   console.log(`当前速度：${JSON.stringify(player.body.velocity)}`);

    // });

    // 配置碰撞检测

    Matter.Events.on(this.physics.engine, 'collisionStart', (event) => {
      event.pairs.forEach(pair => {
        const bullets = this.state.bullets;
        const boxes = this.state.textboxes;

        // 检测子弹与文本框碰撞
        const bullet = bullets.find(b => [pair.bodyA, pair.bodyB].includes(b.body));
        const box = boxes.find(t => [pair.bodyA, pair.bodyB].includes(t.body));

        if (bullet && box) {
          // 处理碰撞逻辑
          World.remove(this.physics.engine.world, bullet.body);
          this.state.bullets.splice(bullets.indexOf(bullet), 1);

          // 标记文本框被击中
          box.hitCount++;
        }
      });
    });

    // // 注册移动消息
    this.onMessage("move", (client, direction) => {
      const player = this.state.players.get(client.sessionId);
      // 根据方向更新坐标
      switch (direction) {
        case "left":
          player.x -= this.length;
          break;
        case "right":
          player.x += this.length;
          break;
        case "up":
          player.y += this.length;
          break;
        case "down":
          player.y -= this.length;
          break;
      }
    });

    // 注册射击消息
    this.onMessage("shoot", (client, data) => {
      const player = this.state.players.get(client.sessionId);
      if (!player) return;

      // 创建新子弹（示例使用玩家当前方向）
      const bullet = new Bullet(
        player.x,
        player.y,
        player.direction
      );
      bullet.addBody(this.physics.engine);

      this.state.bullets.push(bullet);
    });

    // 注册旋转消息
    this.onMessage("rotate", (client, direction) => {
      const player = this.state.players.get(client.sessionId);
      if (!player) return;

      player.direction = direction;
    });
  }
  private updateBezierPaths() {
    const now = Date.now();

    this.state.textboxes.forEach(box => {
      if (!box.curve) return;

      const elapsed = now - box.startTime;
      const progress = Math.min(elapsed / box.duration, 1); // 标准化进度[0,1]

      if (progress >= 1) {
        if (box.loop) {
          box.startTime = now; // 重置计时器实现循环
        } else {
          return;
        }
      }

      // 匀速运动：直接根据进度比例获取位置
      const t = box.loop ? progress % 1 : progress;
      const point = box.curve.get(t);

      Body.setPosition(box.body, point);
    });
  }
  // 同步物理状态到Schema
  private syncPhysicsState() {
    this.state.players.forEach(player => {
      player.body.position.x = player.x;
      player.body.position.y = player.y;
      Body.setAngle(player.body, player.direction * (Math.PI / 180)); // 同步旋转角度
    });

    this.state.bullets.forEach(bullet => {
      bullet.x = bullet.body.position.x;
      bullet.y = bullet.body.position.y;
    });

    this.state.textboxes.forEach(box => {
      box.x = box.body.position.x;
      box.y = box.body.position.y;
    });
  }

  onJoin(client: Client) {
    console.log(`Player ${client.sessionId} joined!`);
    const player = new Player();
    player.addBody(this.physics.engine);
    // 初始化玩家位置
    this.state.players.set(client.sessionId, player);
  }

  onLeave(client: Client) {
    this.state.players.delete(client.sessionId);
    console.log(`Player ${client.sessionId} left!`);
  }
}

function getPoints(w: number, h: number) {
  const halfW = w / 2
  const halfH = h / 2

  let x1, y1, x2, y2, x3, y3, x4, y4
  let cx, cy
  // 从-halfw 到 halfw随机
  while (!x1) {
    x1 = getRandom(-halfW, halfW)
    cx = x1 < 0 ? halfW : -halfW
  }
  while (!y1) {
    y1 = getRandom(-halfH, halfH)
    cy = y1 < 0 ? halfH : -halfH
  }
  while (!x2) {
    x2 = getRandom(0, cx)
  }
  while (!y2) {
    y2 = getRandom(0, cy)
  }
  if (Math.random() < 0.5) {
    x2 = cx
  } else {
    y2 = cy
  }
  if (Math.random() < 0.5) {
    x1 = -cx
  } else {
    y1 = -cy
  }
  x3 = getRandom(-halfW, halfW)
  y3 = getRandom(-halfH, halfH)
  x4 = getRandom(-halfW, halfW)
  y4 = getRandom(-halfH, halfH)
  return [
    [x1, y1],
    [x3, y3],
    [x4, y4],
    [x2, y2]
  ]
}

const getRandom = (min: number, max: number) => {
  return Math.random() * (max - min + 1) + min
}